From 15b9b5a0776b8246917e95201e448fa70ee0a6ba Mon Sep 17 00:00:00 2001 From: robertl Date: Sat, 13 Dec 2003 07:13:46 +0000 Subject: [PATCH] Three changes: 1) Lay groundwork in GPX parser for context sensitive switching. 2) Add route reversal. 3) move painful test to 'torture' target from testo (you're welcome, Ron) --- gpsbabel/Makefile | 19 ++- gpsbabel/defs.h | 9 ++ gpsbabel/filter_vecs.c | 6 + gpsbabel/gpx.c | 292 ++++++++++++++++++++++++++++----------- gpsbabel/queue.h | 2 + gpsbabel/reverse_route.c | 66 +++++++++ gpsbabel/route.c | 21 ++- gpsbabel/testo | 37 +++-- gpsbabel/torture_test | 27 ++++ gpsbabel/vmem.c | 61 ++++++++ 10 files changed, 433 insertions(+), 107 deletions(-) create mode 100644 gpsbabel/reverse_route.c create mode 100755 gpsbabel/torture_test create mode 100644 gpsbabel/vmem.c diff --git a/gpsbabel/Makefile b/gpsbabel/Makefile index 53ce2e684..62944f090 100644 --- a/gpsbabel/Makefile +++ b/gpsbabel/Makefile @@ -20,7 +20,7 @@ FMTS=magproto.o gpx.o geo.o mapsend.o mapsource.o \ xcsv.o gcdb.o tiger.o internal_styles.o easygps.o quovadis.o \ gpilots.o saroute.o navicache.o psitrex.o geoniche.o -FILTERS=position.o duplicate.o arcdist.o polygon.o smplrout.o +FILTERS=position.o duplicate.o arcdist.o polygon.o smplrout.o reverse_route.o JEEPS=jeeps/gpsapp.o jeeps/gpscom.o \ jeeps/gpsmath.o jeeps/gpsmem.o \ @@ -33,7 +33,7 @@ JEEPS=jeeps/gpsapp.o jeeps/gpscom.o \ COLDSYNC=coldsync/util.o coldsync/pdb.o LIBOBJS = queue.o route.o waypt.o filter_vecs.o util.o vecs.o mkshort.o \ - csv_util.o grtcirc.o \ + csv_util.o grtcirc.o vmem.o \ $(COLDSYNC) $(GARMIN) $(JEEPS) $(FMTS) $(FILTERS) OBJS = main.o $(LIBOBJS) @@ -51,6 +51,13 @@ main.o: clean: rm -f $(OBJS) gpsbabel gpsbabel.exe +check: + ./testo + +torture: + ./testo + ./torture_test + # # This will only work on UNIX-like substances. # @@ -70,10 +77,10 @@ dep: (echo -n "internal_styles.c: mkstyle.sh " ; echo style/*.style ; /bin/echo -e '\t./mkstyle.sh > $@ || (rm -f $@ ; exit 1)' ) >> /tmp/dep echo Edit Makefile and bring in /tmp/dep -VERSIONU=1_1_1_beta10082003 -VERSIOND=1.1.1_beta10082003 -VERSIONU=1_2_1 -VERSIOND=1.2.1 +VERSIONU=1_2_1_beta12132003 +VERSIOND=1.2.1_beta12132003 +#VERSIONU=1_2_1 +#VERSIOND=1.2.1 release: ./chkdoc diff --git a/gpsbabel/defs.h b/gpsbabel/defs.h index 2b5ee3c6a..45cad67fe 100644 --- a/gpsbabel/defs.h +++ b/gpsbabel/defs.h @@ -245,6 +245,15 @@ void setshort_mustupper(void *, int n); void setshort_mustuniq(void *, int n); void setshort_whitespace_ok(void *, int n); +typedef struct vmem { + void *mem; /* visible memory object */ + size_t size; /* allocated size of object */ +} vmem_t; +vmem_t vmem_alloc(size_t); +void vmem_free(vmem_t*); +void vmem_realloc(vmem_t*, size_t); + + #define ARGTYPE_UNKNOWN 0 #define ARGTYPE_INT 0x00000001 #define ARGTYPE_FLOAT 0x00000002 diff --git a/gpsbabel/filter_vecs.c b/gpsbabel/filter_vecs.c index 3da4816f9..6453dc8de 100644 --- a/gpsbabel/filter_vecs.c +++ b/gpsbabel/filter_vecs.c @@ -34,6 +34,7 @@ extern filter_vecs_t duplicate_vecs; extern filter_vecs_t arcdist_vecs; extern filter_vecs_t polygon_vecs; extern filter_vecs_t routesimple_vecs; +extern filter_vecs_t reverse_route_vecs; static fl_vecs_t filter_vec_list[] = { @@ -67,6 +68,11 @@ fl_vecs_t filter_vec_list[] = { "simplify", "Simplify routes", }, + { + &reverse_route_vecs, + "reverse", + "Reverse stops within routes", + }, { NULL, NULL, diff --git a/gpsbabel/gpx.c b/gpsbabel/gpx.c index 09f29e3c8..dfcce9418 100644 --- a/gpsbabel/gpx.c +++ b/gpsbabel/gpx.c @@ -63,6 +63,7 @@ static const char *gpx_creator; static char *gpx_email = NULL; static char *gpx_author = NULL; +vmem_t current_tag; static waypoint *wpt_tmp; static FILE *fd; @@ -84,6 +85,84 @@ static route_head *rte_head; #define MYNAME "GPX" #define MY_CBUF 4096 +typedef enum { + tt_unknown = 0, + tt_ele, + tt_name, + tt_gpx, + tt_email, + tt_author, + tt_wpt, + tt_desc, + tt_cmt, + tt_rte, + tt_rtept, + tt_trk, + tt_trkpt, + tt_number, + tt_time, + tt_url, + tt_urlname, + tt_sym, + tt_cache_type, + tt_cache_name, + tt_cache_container, + tt_cache_difficulty, + tt_cache_terrain, + tt_cache_log, + tt_cache_log_wpt, + tt_cache_exported, + tt_cache_travelbugs +} tag_type; + +typedef struct tag_mapping { + tag_type tag_type; + const char *tag_name; +} tag_mapping; + +tag_mapping tag_map[] = { + { tt_ele, "ele" }, + { tt_name, "name" }, + { tt_gpx, "gpx" }, + { tt_email, "email" }, + { tt_author, "author" }, + { tt_wpt, "wpt" }, + { tt_desc, "desc" }, + { tt_cmt, "cmt" }, + { tt_rte, "rte" }, + { tt_rtept, "rtept" }, + { tt_trk, "trk" }, + { tt_trkpt, "trkpt" }, + { tt_number, "number" }, + { tt_time, "time" }, + { tt_url, "url" }, + { tt_urlname, "urlname" }, + { tt_sym, "sym" }, + { tt_cache_type, "groundspeak:type" }, + { tt_cache_name, "groundspeak:name" }, + { tt_cache_container, "groundspeak:container" }, + { tt_cache_difficulty, "groundspeak:difficulty" }, + { tt_cache_terrain, "groundspeak:terrain" }, + { tt_cache_log, "groundspeak:log" }, + { tt_cache_log_wpt, "groundspeak:log_wpt" }, + { tt_cache_exported, "groundspeak:exported" }, + { tt_cache_travelbugs, "groundspeak:travelbugs" }, + {0} +}; + +static tag_type +get_tag(const char *t) +{ + tag_mapping *tm; + + for (tm = tag_map; tm->tag_type != 0; tm++) { + if (0 == strcmp(tm->tag_name, t)) { + return tm->tag_type; + } + } + return tt_unknown; +} + static void tag_gpx(const char **attrv) { @@ -232,114 +311,124 @@ tag_log_wpt(const char **attrv) static void gpx_start(void *data, const char *el, const char **attr) { - - if (strcmp(el, "ele") == 0) { + char *e; + char *ep; + vmem_realloc(¤t_tag, strlen(current_tag.mem) + 1 + strlen(el)); + e = current_tag.mem; + ep = e + strlen(e); + *ep++ = '/'; + strcpy(ep, el); + switch (get_tag(el)) { + case tt_ele: in_ele++; - } - else if (strcmp(el, "name") == 0) { + break; + case tt_name: in_name ++; - } - else if (strcmp(el, "gpx") == 0) { + break; + case tt_gpx: tag_gpx(attr); - } - else if (strcmp(el, "email") == 0 ) { + break; + case tt_email: in_email++; - } - else if (strcmp(el, "author") == 0 ) { + break; + case tt_author: in_author++; - } - else if (strcmp(el, "wpt") == 0) { + break; + case tt_wpt: in_wpt++; tag_wpt(attr); - } - else if (strcmp(el, "desc") == 0) { + break; + case tt_desc: in_desc++; - } - else if (strcmp(el, "cmt") == 0) { + break; + case tt_cmt: in_cmt++; - } - else if (strcmp(el, "rte") == 0) { + break; + case tt_rte: rte_head = route_head_alloc(); route_add_head(rte_head); in_rte++; - } - else if (strcmp(el, "rtept") == 0) { + break; + case tt_rtept: in_rtept++; tag_wpt(attr); - } - else if (strcmp(el, "trk") == 0) { + break; + case tt_trk: trk_head = route_head_alloc(); route_add_head(trk_head); in_trk++; - } - else if (strcmp(el, "trkpt") == 0) { + break; + case tt_trkpt: in_trkpt++; tag_wpt(attr); - } - else if (strcmp(el, "number") == 0) { + break; + case tt_number: in_number++; - } - else if (strcmp(el, "time") == 0) { + break; + case tt_time: in_time++; - } - else if (strcmp(el, "url") == 0) { + break; + case tt_url: in_url++; - } - else if (strcmp(el, "urlname") == 0) { + break; + case tt_urlname: in_urlname++; - } - else if (strcmp(el, "sym") == 0) { + break; + case tt_sym: in_icon++; - } - else if (strcmp(el, "groundspeak:type") == 0) { + break; + case tt_cache_type: in_gs_type++; in_something_else++; start_something_else( el, attr ); - } - else if (strcmp(el, "groundspeak:name") == 0) { + break; + case tt_cache_name: in_gs_name++; in_something_else++; start_something_else( el, attr ); - } - else if (strcmp(el, "groundspeak:container") == 0) { + break; + case tt_cache_container: in_gs_container++; in_something_else++; start_something_else( el, attr ); - } - else if (strcmp(el, "groundspeak:difficulty") == 0) { + break; + case tt_cache_difficulty: in_gs_diff++; in_something_else++; start_something_else( el, attr ); - } - else if (strcmp(el, "groundspeak:terrain") == 0) { + break; + case tt_cache_terrain: in_gs_terr++; in_something_else++; start_something_else( el, attr ); - } - else if (strcmp(el, "groundspeak:log") == 0) { + break; + case tt_cache_log: in_gs_log++; in_something_else++; start_something_else( el, attr ); - } - else if (strcmp(el, "groundspeak:log_wpt") == 0) { + break; + case tt_cache_log_wpt: in_gs_log_wpt++; if (opt_logpoint) tag_log_wpt(attr); in_something_else++; start_something_else( el, attr ); - } - else if (strcmp(el, "groundspeak:exported") == 0) { + break; + case tt_cache_exported: in_gs_exported++; /* no start_something_else because the old date is eaten */ - } - else if (strcmp(el, "groundspeak:travelbugs") == 0) { + break; + case tt_cache_travelbugs: in_gs_tbugs++; in_something_else++; start_something_else( el, attr ); - } - else if (in_wpt) { - in_something_else++; - start_something_else( el, attr ); + break; + default: + if (in_wpt) { + in_something_else++; + start_something_else( el, attr ); + } + break; } } @@ -461,7 +550,15 @@ xml_parse_time( char *cdatastr ) static void gpx_end(void *data, const char *el) { + char *s = strrchr(current_tag.mem, '/'); + + if (strcmp(s + 1, el)) { + fprintf(stderr, "Mismatched tag %s\n", el); + } + *s = 0; + float x; + if (in_cdata) { if (in_name && in_wpt && !in_gs_tbugs) { wpt_tmp->shortname = xstrdup(cdatastr); @@ -556,84 +653,111 @@ gpx_end(void *data, const char *el) in_cdata--; memset(cdatastr, 0, MY_CBUF); } - if (strcmp(el, "wpt") == 0) { + switch (get_tag(el)) { + case tt_wpt: if ( !wpt_tmp->gc_data.exported ) { wpt_tmp->gc_data.exported = file_time; } waypt_add(wpt_tmp); in_wpt--; logpoint_ct = 0; - } - else if (strcmp(el, "rte") == 0) { + break; + case tt_rte: in_rte--; - } else if (strcmp(el, "rtept") == 0) { + break; + case tt_rtept: route_add_wpt(rte_head, wpt_tmp); in_rtept--; - } else if (strcmp(el, "trk") == 0) { + break; + case tt_trk: in_trk--; - } else if (strcmp(el, "trkpt") == 0) { + break; + case tt_trkpt: route_add_wpt(trk_head, wpt_tmp); in_trkpt--; - } else if (strcmp(el, "number") == 0) { + break; + case tt_number: in_number--; - } else if (strcmp(el, "name") == 0) { + break; + case tt_name: in_name--; - } else if (strcmp(el, "desc") == 0) { + break; + case tt_desc: in_desc--; - } else if (strcmp(el, "email") == 0 ) { + break; + case tt_email: in_email--; - } else if (strcmp(el, "author") == 0 ) { + break; + case tt_author: in_author--; - } else if (strcmp(el, "cmt") == 0) { + break; + case tt_cmt: in_cmt--; - } else if (strcmp(el, "ele") == 0) { + break; + case tt_ele: in_ele--; - } else if (strcmp(el, "time") == 0) { + break; + case tt_time: in_time--; - } else if (strcmp(el, "url") == 0) { + break; + case tt_url: in_url--; - } else if (strcmp(el, "urlname") == 0) { + break; + case tt_urlname: in_urlname--; - } else if (strcmp(el, "sym") == 0) { + break; + case tt_sym: in_icon--; - } else if (strcmp(el, "groundspeak:type") == 0) { + break; + case tt_cache_type: in_gs_type--; in_something_else--; end_something_else(); - } else if (strcmp(el, "groundspeak:name") == 0) { + break; + case tt_cache_name: in_gs_name--; in_something_else--; end_something_else(); - } else if (strcmp(el, "groundspeak:container") == 0) { + break; + case tt_cache_container: in_gs_container--; in_something_else--; end_something_else(); - } else if (strcmp(el, "groundspeak:difficulty") == 0) { + break; + case tt_cache_difficulty: in_gs_diff--; in_something_else--; end_something_else(); - } else if (strcmp(el, "groundspeak:terrain") == 0) { + break; + case tt_cache_terrain: in_gs_terr--; in_something_else--; end_something_else(); - } else if (strcmp(el, "groundspeak:log") == 0) { + break; + case tt_cache_log: in_gs_log--; in_something_else--; end_something_else(); - } else if (strcmp(el, "groundspeak:log_wpt") == 0) { + break; + case tt_cache_log_wpt: in_gs_log_wpt--; in_something_else--; end_something_else(); - } else if (strcmp(el, "groundspeak:exported") == 0) { + break; + case tt_cache_exported: in_gs_exported--; /* no end_something_else because the old date is eaten */ - } else if (strcmp(el, "groundspeak:travelbugs") == 0) { + break; + case tt_cache_travelbugs: in_gs_tbugs--; in_something_else--; end_something_else(); - } else if (in_wpt) { + break; + default: + if (in_wpt) { in_something_else--; end_something_else(); + } } } @@ -726,6 +850,7 @@ gpx_rd_init(const char *fname) file_time = 0; + current_tag = vmem_alloc(1); psr = XML_ParserCreate(NULL); if (!psr) { @@ -740,6 +865,7 @@ gpx_rd_init(const char *fname) static void gpx_rd_deinit(void) { + vmem_free(¤t_tag); if ( cdatastr ) { xfree(cdatastr); cdatastr = NULL; diff --git a/gpsbabel/queue.h b/gpsbabel/queue.h index d7bfffd17..7392ce6d2 100644 --- a/gpsbabel/queue.h +++ b/gpsbabel/queue.h @@ -35,6 +35,8 @@ queue * dequeue(queue *element); #define ENQUEUE_TAIL(listhead, element) \ enqueue(element, (listhead)->prev) +#define ENQUEUE_HEAD(listhead, element) \ + enqueue(element, listhead) #define QUEUE_FOR_EACH(listhead, element, tmp) \ for ((element) = QUEUE_FIRST(listhead); \ diff --git a/gpsbabel/reverse_route.c b/gpsbabel/reverse_route.c new file mode 100644 index 000000000..b9d882435 --- /dev/null +++ b/gpsbabel/reverse_route.c @@ -0,0 +1,66 @@ +/* + Route reversal filter. + + Copyright (C) 2003 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ +#include +#include "defs.h" + +#define MYNAME "Route reversal filter" + +static +arglist_t reverse_route_args[] = { + {0, 0, 0, 0} +}; + +void +reverse_route_head( const route_head *rte ) +{ + route_reverse(rte); +} + +void +reverse_route_process( void ) +{ + route_disp_all( reverse_route_head, NULL, NULL ); +} + +void +reverse_route_init(const char *args) +{ + switch (global_opts.objective) { + case rtedata: break; + case trkdata: break; + default: + fatal(MYNAME ": This filter only works in track " + "or route (-t or -r) mode."); + } +} + +void +reverse_route_deinit(void) +{ + /* do nothing */ +} + +filter_vecs_t reverse_route_vecs = { + reverse_route_init, + reverse_route_process, + reverse_route_deinit, + reverse_route_args +}; diff --git a/gpsbabel/route.c b/gpsbabel/route.c index 70c597bb9..74cfd57a0 100644 --- a/gpsbabel/route.c +++ b/gpsbabel/route.c @@ -96,13 +96,28 @@ void route_disp (const route_head *rh, waypt_cb cb ) { queue *elem, *tmp; + if (!cb) { + return; + } QUEUE_FOR_EACH(&rh->waypoint_list, elem, tmp) { waypoint *waypointp; waypointp = (waypoint *) elem; (*cb)(waypointp); } -} +} + +void +route_reverse(const route_head *rte_hd) +{ + /* Cast away const-ness */ + route_head *rh = (route_head *) rte_hd; + queue *elem, *tmp; + QUEUE_FOR_EACH(&rh->waypoint_list, elem, tmp) { + ENQUEUE_HEAD(&rh->waypoint_list, dequeue(elem)); + } +} + void route_disp_all(route_hdr rh, route_trl rt, waypt_cb wc) { @@ -110,9 +125,9 @@ route_disp_all(route_hdr rh, route_trl rt, waypt_cb wc) QUEUE_FOR_EACH(&my_route_head, elem, tmp) { const route_head *rhp; rhp = (route_head *) elem; - (*rh)(rhp); + if (rh) (*rh)(rhp); route_disp(rhp, wc); - (*rt)(rhp); + if (rt) (*rt)(rhp); } } void diff --git a/gpsbabel/testo b/gpsbabel/testo index 34292c02c..63264d75a 100755 --- a/gpsbabel/testo +++ b/gpsbabel/testo @@ -428,18 +428,25 @@ ${PNAME} -r -i gpx -f reference/route/route.gpx \ compare ${TMPDIR}/simplify.txt reference/simplify_output.txt # -# This is nasty. If we have a dictionary handy, treat it as a list of -# waypoints and reduce all the names to eight characters. Fewer chars -# results in lost waypoints currently and that's a defect. -# -DICT=/usr/share/dict/words -if [ -f $DICT ]; -then - WORDS=`cat $DICT | wc -l` - SWORDS=`${PNAME} -i gpsdrive -f $DICT -o gpsdrive,snlen=8 -F /dev/fd/1 | wc -l` - if [ $WORDS -ne $SWORDS ]; - then - echo "Shortname reduction failed." - exit 1 - fi -fi +# Route reversal filter. Do it twice and be sure we get what we +# started with. +# +rm -f ${TMPDIR}/reverse1.arc ${TMPDIR}/reverse2.arc ${TMPDIR}/reference.arc +${PNAME} -r -i gpx -f reference/route/route.gpx \ + -o arc -F ${TMPDIR}/reference.arc +${PNAME} -r -i gpx -f reference/route/route.gpx \ + -x reverse \ + -o arc -F ${TMPDIR}/reverse1.arc +${PNAME} -r -i gpx -f reference/route/route.gpx \ + -x reverse \ + -x reverse \ + -o arc -F ${TMPDIR}/reverse2.arc +# Verify the first and last are the same +compare ${TMPDIR}/reference.arc ${TMPDIR}/reverse2.arc +# Verify the first and second are different. +${DIFF} ${TMPDIR}/reverse1.arc ${TMPDIR}/reverse2.arc > /dev/null && { + echo ERROR Failed reversal test. + exit 1 +} + +exit 0 diff --git a/gpsbabel/torture_test b/gpsbabel/torture_test new file mode 100755 index 000000000..66095cf55 --- /dev/null +++ b/gpsbabel/torture_test @@ -0,0 +1,27 @@ + +PNAME=${PNAME:-./gpsbabel} +DIFF=${DIFF:-diff} + +TMPDIR=/tmp/gpsbabel.$$ +mkdir -p $TMPDIR +trap "rm -fr $TMPDIR" 0 1 2 3 15 + +# +# This is nasty. If we have a dictionary handy, treat it as a list of +# waypoints and reduce all the names to eight characters. Fewer chars +# results in lost waypoints currently and that's a defect. +# +DICT=/usr/share/dict/words +if [ -f $DICT ]; +then + WORDS=`cat $DICT | wc -l` + SWORDS=`${PNAME} -i gpsdrive -f $DICT -o gpsdrive,snlen=8 -F /dev/fd/1 | + wc -l` + if [ $WORDS -ne $SWORDS ]; + then + echo "Shortname reduction failed." + exit 1 + fi +fi + +exit 0 diff --git a/gpsbabel/vmem.c b/gpsbabel/vmem.c new file mode 100644 index 000000000..bef4d970d --- /dev/null +++ b/gpsbabel/vmem.c @@ -0,0 +1,61 @@ +/* + vmem utilities. Manipulate allocated object optimized for + long-term persistence over raw speed. + + Copyright (C) 2003 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include + +vmem_t +vmem_alloc(size_t size) +{ + vmem_t vm; + vm.mem = xmalloc(size); + vm.size = size; + return vm; +} + +void +vmem_free(vmem_t *vm) +{ + xfree(vm->mem); + vm->mem = NULL; + vm->size = 0; + return; +} + +/* + * We never shrink a vmem object on the premise that over time, object + * will only grow for a while then reach a steady state. + */ +void +vmem_realloc(vmem_t *vm, size_t size) +{ + /* + * Reallocate only if we must. + */ + if (size > vm->size) { + vm->mem = xrealloc(vm->mem, size + 20); + vm->size = size; + } + return; +} + + -- 2.30.2